﻿#region Copyright (c) 2000-2013 Developer Express Inc.
/*
{*******************************************************************}
{                                                                   }
{       Developer Express .NET Component Library                    }
{                                                                   }
{                                                                   }
{       Copyright (c) 2000-2013 Developer Express Inc.              }
{       ALL RIGHTS RESERVED                                         }
{                                                                   }
{   The entire contents of this file is protected by U.S. and       }
{   International Copyright Laws. Unauthorized reproduction,        }
{   reverse-engineering, and distribution of all or any portion of  }
{   the code contained in this file is strictly prohibited and may  }
{   result in severe civil and criminal penalties and will be       }
{   prosecuted to the maximum extent possible under the law.        }
{                                                                   }
{   RESTRICTIONS                                                    }
{                                                                   }
{   THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES           }
{   ARE CONFIDENTIAL AND PROPRIETARY TRADE                          }
{   SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS   }
{   LICENSED TO DISTRIBUTE THE PRODUCT AND ALL ACCOMPANYING .NET    }
{   CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY.                 }
{                                                                   }
{   THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED      }
{   FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE        }
{   COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE       }
{   AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT  }
{   AND PERMISSION FROM DEVELOPER EXPRESS INC.                      }
{                                                                   }
{   CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON       }
{   ADDITIONAL RESTRICTIONS.                                        }
{                                                                   }
{*******************************************************************}
*/
#endregion Copyright (c) 2000-2013 Developer Express Inc.

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using DevExpress.Data.Browsing;
using UColor.Core.Helpers;
using DevExpress.Xpf.Core;
namespace UColor.WPF.Helpers {
	public class KeyboardFocusHelper {
		public static readonly DependencyProperty FocusableProperty;
		static DependencyPropertyDescriptor contentDescriptor;
		static KeyboardFocusHelper() {
			Type ownerType = typeof(KeyboardFocusHelper);
#if SL
			contentDescriptor = DependencyPropertyDescriptor.FromProperty(TypeDescriptor.GetProperties(typeof(ContentPresenter))["Content"]);
#else
			contentDescriptor = DependencyPropertyDescriptor.FromProperty(ContentPresenter.ContentProperty, typeof(ContentPresenter));
#endif
			FocusableProperty = DependencyProperty.RegisterAttached("Focusable", typeof(bool?), ownerType, new PropertyMetadata(null, OnFocusableChanged));
		}
		public static void SetFocusable(DependencyObject element, bool value) { element.SetValue(FocusableProperty, value); }
		public static bool? GetFocusable(DependencyObject element) { return (bool?)element.GetValue(FocusableProperty); }
		static void OnFocusableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			if(((bool?)e.NewValue).HasValue) {
				if(((bool?)e.NewValue).Value) {
					MakeFocusableCore(d, true);
				} else {
					UniversalControl universalControl = d as UniversalControl;
					if(universalControl != null) {
						if(universalControl.IsInVisualTree()) {
							MakeUnfocusable(d);
						} else {
							ResubscribeToActualLoaded(universalControl);
						}
					} else {
						FrameworkElement element = d as FrameworkElement;
						if(element.IsInVisualTree()) {
							MakeUnfocusable(d);
						} else {
							ResubscribeToLoaded(element);
						}
					}
				}
			}
		}
		static void ResubscribeToActualLoaded(UniversalControl universalControl) {
			universalControl.ActualLoaded -= OnLoaded;
			universalControl.ActualLoaded += OnLoaded;
		}
		static void ResubscribeToLoaded(FrameworkElement universalControl) {
			universalControl.Loaded -= OnLoaded;
			universalControl.Loaded += OnLoaded;
		}
		static void OnLoaded(object sender, EventArgs e) {
			if(sender is UniversalControl) {
				((UniversalControl)sender).ActualLoaded -= OnLoaded;
			} else {
				if(sender is FrameworkElement) {
					((FrameworkElement)sender).Loaded -= OnLoaded;
				}
			}
			MakeUnfocusable(sender as DependencyObject);
		}
		static void MakeUnfocusable(DependencyObject d) {
			if(d == null) return;
			if(d is UIElement) {
				if(GetFocusable(d).HasValue && GetFocusable(d).Value) {
					MakeFocusableCore(d, true);
					return;
				} else {
					if(d is FrameworkElement) {
						if(!((FrameworkElement)d).IsInVisualTree()) {
							if(d is UniversalControl) {
								ResubscribeToActualLoaded(d as UniversalControl);
							} else {
								ResubscribeToLoaded((FrameworkElement)d);
							}
							return;
						} else {
							if(d is ContentPresenter) {
								contentDescriptor.AddValueChanged(d, ContentChanged);
								((ContentPresenter)d).Unloaded += OnContentPresenterUnloaded;
							} else {
								MakeFocusableCore(d, false);
							}
						}
					}
				}
			}
			for(int i = 0; i < VisualTreeHelper.GetChildrenCount(d); ++i) {
				MakeUnfocusable(VisualTreeHelper.GetChild(d, i));
			}
		}
		static void OnContentPresenterUnloaded(object sender, RoutedEventArgs e) {
			contentDescriptor.RemoveValueChanged(sender, ContentChanged);
		}
		static void MakeFocusableCore(DependencyObject d, bool newValue) {
#if !SL
			if(d is UIElement) {
				((UIElement)d).Focusable = newValue;
			}
#endif
			if(d is Control) {
				((Control)d).IsTabStop = newValue;
			}
		}
		static void ContentChanged(object sender, EventArgs e) {
			MakeFocusableCore(sender as DependencyObject, false);
			MakeUnfocusable(((ContentPresenter)sender).Content as DependencyObject);
		}
	}
}
